Skip to main content

Resource Design

Resource Naming Conventions

When designing RESTful APIs, the URLs (endpoints) represent resources (things/entities in your system), not actions.

  • Resources = nouns → represent objects, collections, or entities.
  • Actions = verbs → represent operations (like "getUser", "createOrder").

In REST, we avoid verbs in endpoint paths because the HTTP method (GET, POST, PUT, DELETE) already defines the action.

Why use nouns instead of verbs?

  1. Consistency → Easy to understand across APIs.
  2. Clarity → URL describes what the resource is, not what to do with it.
  3. Flexibility → Operations are handled by HTTP methods instead of encoding them in the URL.
  4. REST Best Practice → Keeps endpoints clean, predictable, and uniform.

Example of API Naming

Bad (using verbs in path):

/getUsers
/createUser
/deleteUser/123

Problem → Verb in path duplicates what HTTP method already specifies.

Good (using nouns):

GET    /users          → fetch all users
POST /users → create a new user
GET /users/123 → fetch user with ID 123
PUT /users/123 → update user with ID 123
DELETE /users/123 → delete user with ID 123

Explanation: users is a resource (noun), HTTP method defines the action.

Rules of Thumb for Resource Naming

  1. Use nouns (plural form)

    • /users, /orders, /products
    • Not /getUser, /createOrder
  2. Use hierarchical structure for relationships

    • /users/123/orders/77
  3. Use lowercase with hyphens (for readability)

    • /user-profiles not /UserProfiles or /user_profiles
  4. Avoid actions/verbs in URLs

    • Don't use /activateAccount
    • Instead → POST /accounts/123/activation
  5. Keep it consistent across the API

    • Don’t mix plural /users and singular /order in same design.

When to Use Singular Resource Names?

If the API represents a unique, singular resource, it might make sense to use a singular name. For example, an API for a single user profile might use /profile instead of /profiles.

Request & Response Structure

Request Structure

The request sent by the client typically consists of the following components:

  • URL: The endpoint or resource being accessed.
  • HTTP Method: The type of action to be performed (GET, POST, PUT, DELETE).
  • Headers: Contain metadata about the request (e.g., content type, authentication).
  • Body: For methods like POST or PUT, the body contains the actual data being sent, typically in JSON format.

Response Structure

The server's response will also be in JSON format, containing the result of the request. The response typically includes:

  • Status Code: Indicates the success or failure of the request (e.g., 200 OK, 201 Created, 400 Bad Request).
  • Headers: Provides additional information about the response (e.g., content type, caching).
  • Body: Contains the data or message returned by the server.

Path Parameters

Path parameters (also called URL parameters or route parameters) are used to identify specific resources in an API. They are part of the URL path itself and are usually mandatory.

  • Mandatory (usually required to access the resource).
  • Identify specific resource(s).
  • Part of the URL path.
  • Usually represented in curly braces {} in API documentation.

When to use:

  • To fetch, update, or delete specific resources.
  • When the resource hierarchy is clear: /users/{userId}/orders/{orderId}.

Query Parameters

Query parameters are used to filter, sort, or paginate resources. They appear after the ? in the URL and are usually optional.

  • Optional (often).
  • Used for filtering, sorting, pagination, or searching.
  • Not part of the resource path; instead, they refine the request.
  • Key-value pairs, separated by &.

Path Parameters vs Query Parameters

FeaturePath ParameterQuery Parameter
PurposeIdentify specific resourceFilter, sort, or refine resource
MandatoryUsually yesUsually optional
Part of URLYesNo (after ?)
Example URL/users/123/users?role=admin&status=active
Best use caseFetch, update, delete single resourceFilter, sort, paginate resource list
Impact on cachingPath usually creates new resource URL (cache key)Same path, different query can be cached separately

Pagination

Pagination is the process of splitting large sets of data into smaller chunks (pages) so that the client can request and navigate through them efficiently.

There are three common strategies in REST API design:

Limit & Offset Pagination

This is the most common and simplest form of pagination.

  • limit → how many items to return per request.
  • offset → how many items to skip before starting to return results.
GET /api/v1/products?limit=10&offset=20

limit=10 → return 10 products offset=20 → skip the first 20 products, start from the 21st

Advantages:

  • Easy to implement
  • Familiar and intuitive

Disadvantages:

  • Inefficient for large offsets (e.g., offset=100000 requires skipping a lot of rows).
  • Data inconsistency if records are inserted/deleted between requests.

Page-based Pagination

This is a variant of limit/offset where instead of offset, you use page numbers.

GET /api/v1/products?page=3&limit=10
  • page=3 → return the 3rd page
  • limit=10 → 10 items per page

This internally translates to:

  • skip = (page - 1) × limit → (3-1)×10 = 20
  • same as offset=20

Advantages:

  • User-friendly ("Page 1, Page 2...")
  • Simple for UI navigation Disadvantages:
  • Suffers from the same large dataset inefficiency as offset

Cursor-based Pagination (a.k.a. Keyset Pagination)

Instead of numeric offsets, this uses a pointer (cursor) to the last item fetched. The cursor is usually a unique, sequential, or sortable field (like id or created_at).

GET /api/v1/products?limit=10&cursor=21
  • cursor=21 → start after product with ID=21
  • limit=10 → return next 10 items

Advantages:

  • Efficient for large datasets
  • Consistent results even if new records are inserted/deleted
  • Scales well for APIs with continuous scrolling (e.g., Twitter feed)

Disadvantages:

  • More complex to implement
  • Cursors must be securely encoded (not just raw IDs)

Filtering

Filtering allows clients to narrow down results based on specific fields or conditions.

  • Use query parameters for filters.
  • Support multiple filters.
  • Use consistent naming.
  • Consider operators for ranges, dates, etc.
GET /api/v1/products?category=electronics&minPrice=100&maxPrice=1000&brand=sony

Operators (Advanced Filtering):

  • price[gt]=100 → greater than 100
  • price[lte]=1000 → less than or equal to 1000
  • created_at[between]=2023-01-01,2023-12-31
GET /api/v1/orders?status=completed&price[gte]=100&price[lte]=500

Sorting

Sorting defines the order of returned results.

  • Use a sort query parameter.
  • Prefix with - for descending order.
  • Allow multiple fields.
GET /api/v1/products?sort=-price,name
  • First, sort by price (descending).
  • Then, for items with the same price, sort by name (ascending).

Searching

Searching allows clients to perform keyword-based queries across one or multiple fields.

  • Use a general q parameter for free-text search.
  • Allow field-specific searches if needed.
  • For complex cases, integrate with full-text search (Elasticsearch, PostgreSQL tsvector, etc.).
GET /api/v1/products?name=macbook&brand=apple